package common;
import java.io.*;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.*;


public class Shared
{
	public final static String
			CONNECT  = "CONNECT",
			QUIT	 = "QUIT",
			RETRIEVE = "RETR",
			ROBOT	 = "ROBOT",
			QUERY	 = "QUERY";

	public final static int
			PORT 	 = 2,
			SERVER   = 1,
			FILENAME = 1,
			COMMAND  = 0,
			CLIENTNUM= 1,
			FILENUM  = 2;

	public final static int
			DATA_LINE    = 1, 
			CONTROL_LINE = 0;

	public final static String
			HOSTED = "Hosted/",
			DOWNLOADED = "Downloaded/";
	
	/** s t o r e F i l e (   )
	 * ------------------------------------------------------------------------
	 *   The calling class (be it FTP_Client or FTP_Handler) will attempt to
	 *   read from a file and write it to the data socket.
	 */
	public static synchronized void storeFile
			( String filename,
			  DataOutputStream out) 
	{
		FileInputStream file = null;
	
		try {
			file = new FileInputStream( filename );
		} catch ( FileNotFoundException e )
		{
			error( " File \"" + filename + "\" does not exist!" );
			closeObject( out );
			return;
		}

		byte[] buffer = new byte[ 1024 ];
		int bytes = 0;

		System.out.print( " -- Writing file \"" + filename + "\" to socket..." );

		try {
			while ( ( bytes = file.read( buffer ) ) != -1 )
				out.write( buffer, 0, bytes );
		} catch( IOException e ) {
			error( "Connection unexpectedly terminated!" );
		}

		System.out.println( "done." );

		closeObject( file );
		closeObject( out  );
	}

	/** r e t r i e v e F i l e (   )
	 * ------------------------------------------------------------------------
	 *   The calling class (be it FTP_Client or FTP_Handler) will attempt to
	 *   read a file from the data socket and write it to a file.
	 */
	public static synchronized void retrieveFile
			( String filename,
			  DataInputStream in ) 
	{
		FileOutputStream file = null;

		byte[] buffer = new byte[ 1024 ];
		int bytes = 0;
		int iteration = 0;

		System.out.print( " -- Reading file \"" +
						  filename +
						  "\" from socket..." );

		try {
			while ( ( bytes = in.read( buffer ) ) != -1)
			{
				if( iteration++ == 0 )
					 file = new FileOutputStream( filename );
				
				file.write( buffer, 0, bytes );
			}
		} catch( IOException e ) {
			error( "Connection unexpectedly terminated!" );
		}

		if( file != null )
		{
			System.out.println( "done." );
			closeObject( file );
		}
		else
			System.out.println( "\n == WARNING: File \"" +
								filename +
								"\" either does not exist on the server, " +
								"or is empty." );
		
		closeObject( in );
	}
	
	/** s t o r e F i l e (   )
	 * ------------------------------------------------------------------------
	 *   The calling class (be it FTP_Client or FTP_Handler) will attempt to
	 *   read from a file and write it to the data socket.
	 */
	public static synchronized void sendHit
			( Vector<HitInformation> o,
			  OutputStream out) 
	{
		ObjectOutputStream oob = null;
	
		try {
			oob = new ObjectOutputStream( out );
		} catch ( IOException e )
		{
			error( "Cannot create ObjectOuputStream" );
			closeObject( out );
			return;
		}

		System.out.print( " -- Writing Object to socket..." );

		try {
				oob.writeObject( o );
				oob.flush();
		} catch( IOException e ) {
			error( "Connection unexpectedly terminated! you mom!" );
		}

		System.out.println( "done." );
		
		return;
	}
	
	public static synchronized void sendHit
			( HitInformation o,
			OutputStream out) 
	{
		ObjectOutputStream oob = null;

		try {
			oob = new ObjectOutputStream( out );
		} catch ( IOException e )
		{
			error( "Cannot create ObjectOuputStream" );
			closeObject( out );
			return;
		}

		System.out.print( " -- Writing Object to socket..." );

		try {
			oob.writeObject( o );
			oob.flush();
		} catch( IOException e ) {
			error( "Connection unexpectedly terminated! you mom!" );
		}

		System.out.println( "done." );

		return;
	}
	public static synchronized void sendRobotState
		  ( RobotInformation o,
			OutputStream out) 
	{
		ObjectOutputStream oob = null;
		
		try {
			oob = new ObjectOutputStream( out );
		} catch ( IOException e )
		{
			error( "Cannot create ObjectOuputStream" );
			closeObject( out );
			return;
		}
		
		System.out.print( " -- Writing Object to socket..." );
		
		try {
			oob.writeObject( o );
			oob.flush();
		} catch( IOException e ) {
			error( "Connection unexpectedly terminated! you mom!" );
		}
		
		System.out.println( "done." );
		
		return;
	}
	
	/** r e t r i e v e F i l e (   )
	 * ------------------------------------------------------------------------
	 *   The calling class (be it FTP_Client or FTP_Handler) will attempt to
	 *   read a file from the data socket and write it to a file.
	 */
	public static synchronized HitInformation getHit
			( DataInputStream in ) 
	{
		HitInformation result = null;
		BufferedInputStream buff = null;
		ObjectInputStream oib = null;
		
		System.out.println( " Reading Hit object " );
		try{
			buff = new BufferedInputStream( in );
			oib = new ObjectInputStream( buff );
			result = (HitInformation)oib.readObject();
		}catch( Exception e ){
			System.out.println( "Object not found.");
			return null;
		}

		return result;

	}
	
	/** r e t r i e v e F i l e (   )
	 * ------------------------------------------------------------------------
	 *   The calling class (be it FTP_Client or FTP_Handler) will attempt to
	 *   read a file from the data socket and write it to a file.
	 */
	public static synchronized Vector<HitInformation> getHitList
			( DataInputStream in ) 
	{
		Vector<HitInformation> result = null;
		BufferedInputStream buff = null;
		ObjectInputStream oib = null;
		
		System.out.println( " Reading Hit object " );
		try{
			buff = new BufferedInputStream( in );
			oib = new ObjectInputStream( buff );
			result = (Vector<HitInformation>)oib.readObject();
		}catch( Exception e ){
			System.out.println( "Object not found.");
			return null;
		}
		
		return result;

	}
	/** g e t R o b o t (   )
	 * ------------------------------------------------------------------------
	 *   The calling class (be it FTP_Client or FTP_Handler) will attempt to
	 *   read a file from the data socket and write it to a file.
	 */
	public static synchronized RobotInformation getRobotState
			( DataInputStream in ) 
	{
		RobotInformation result = null;
		BufferedInputStream buff = null;
		ObjectInputStream oib = null;
		
		System.out.println( " Reading Robot object " );
		try{
			buff = new BufferedInputStream( in );
			oib = new ObjectInputStream( buff );
			result = (RobotInformation)oib.readObject();
		}catch( Exception e ){
			System.out.println( "Object not found.");
			return null;
		}
		
		return result;
		
	}
	/** c l o s e O b j e c t (   )
	 * ------------------------------------------------------------------------
	 *   Calls the close method on the Object denoted by o.  The object can be
	 *   an instance of the classes: InputStream, OutputStream, ServerSocket,
	 *   or Socket.
	 */
	public static void closeObject( Object o )
	{
		try {
			if( o instanceof InputStream )
				(  (InputStream)o ).close();
			else if( o instanceof OutputStream )
				( (OutputStream)o ).close();
			else if( o instanceof ServerSocket )
				( (ServerSocket)o ).close();
			else if( o instanceof Socket )
				( 		(Socket)o ).close();
		} catch( IOException e ) {
			// If an error occurs, it only means that the object has already
			// been closed, so we can just ignore this error.
		}
	}
	
	/** e r r o r (   ) 
	 * ------------------------------------------------------------------------ 
	 *   Displays the error message denoted by msg.
	 */
	public static void error
			( String msg )
	{
		System.out.println
				( " ** ERROR: " + msg + " **" );
	} 
}
